import * as THREE from "three"
import { SceneChildType } from "../enum/scene.enum"
import Le from "../math/13188"
import LineMesh from "../mesh/LineMesh"
import SnapAxisLine3 from "../three/SnapAxisLine3"
import WebGLScene from "../three/WebGLScene"
import ConstrainedHit from "../utils/ConstrainedHit"
import { RenderLayer } from "../utils/RenderLayers"

var ie = {
  255: "z",
  32768: "y",
  16711680: "x",
  16711935: "xz",
  16724312: "laser",
  16776960: "yellow",
  16777215: "white",
  free: 16777215,
  laser: 16724312,
  white: 16777215,
  x: 16711680,
  xz: 16711935,
  y: 32768,
  yellow: 16776960,
  z: 255
}
var Se = {
  1: "SnapPoint",
  2: "SnapLine",
  3: "AxisAny",
  4: "AxisX",
  5: "AxisY",
  6: "AxisZ",
  7: "Mesh",
  8: "RoomMesh",
  9: "LinePoint",
  10: "LineSegment",
  AxisAny: 3,
  AxisX: 4,
  AxisY: 5,
  AxisZ: 6,
  LinePoint: 9,
  LineSegment: 10,
  Mesh: 7,
  RoomMesh: 8,
  SnapLine: 2,
  SnapPoint: 1
}
export default class AxisLineRenderer {
  scene: WebGLScene
  layer: RenderLayer
  offsetFromMesh: number
  featureColors: { [x: number]: any }
  axesVisibleInConstraints: { [x: number]: boolean }
  linesActive: any[]
  linesFree: any[]
  axesVisible: any[]
  axisMat: THREE.LineBasicMaterial
  render: (e: ConstrainedHit, t: SnapAxisLine3[]) => void
  container: any
  constructor(e, t) {
    ;(this.scene = e),
      (this.layer = t),
      (this.offsetFromMesh = 0.0075),
      (this.featureColors = {
        [Se.AxisX]: ie.x,
        [Se.AxisZ]: ie.z,
        [Se.AxisY]: ie.y
      }),
      (this.axesVisibleInConstraints = {
        [Le.l1.EdgesAndPlanarAxes]: !0,
        [Le.l1.Axes]: !0,
        [Le.l1.PlanarAxes]: !0
      }),
      (this.linesActive = []),
      (this.linesFree = []),
      (this.axesVisible = []),
      (this.axisMat = new THREE.LineBasicMaterial({
        color: 4095,
        linewidth: 1,
        opacity: 0.75,
        transparent: !0,
        depthWrite: !1,
        depthTest: !0
      })),
      (this.render = (e, t) => {
        if (e && this.axesVisibleInConstraints[e.constraint] && t.length > 0) {
          if (t.length !== this.axesVisible.length) this.clearLines()
          else {
            this.axesVisible.every((e, i) => e.equals(t[i])) || this.clearLines()
          }
          if (this.container.parent !== this.scene.scene) {
            for (const e of t) {
              const t = this.getMesh(e)
              t.material.color.setHex(this.featureColors[e.featureType]), this.container.add(t), this.linesActive.push(t)
            }
            ;(this.axesVisible = t.map(e => e)),
              this.scene.addChild(SceneChildType.Root, this.container),
              this.container.position.copy(e.normal).multiplyScalar(this.offsetFromMesh),
              this.container.updateMatrixWorld(!0)
          }
        } else this.clearLines()
      }),
      (this.clearLines = () => {
        if (0 !== this.linesActive.length) {
          for (; this.linesActive.length > 0; ) {
            const e = this.linesActive.pop()
            e && (this.container.remove(e), this.linesFree.push(e))
          }
          this.scene.removeChild(SceneChildType.Root, this.container)
        }
      }),
      (this.container = new THREE.Object3D())
  }
  clearLines: any
  getMesh(e) {
    let t = this.linesFree.pop()
    return t ? t.geometry.setFromPoints([e.start, e.end]) : ((t = new LineMesh(e, this.axisMat.clone())), (t.layers.mask = this.layer.mask)), t
  }
  dispose() {
    for (this.clearLines(); this.linesFree.length > 0; ) {
      const e = this.linesFree.pop()
      e && (this.container.remove(e), e.geometry.dispose(), e.material.dispose())
    }
    ;(this.linesActive = []), (this.linesFree = []), (this.container = null)
  }
}
